﻿// Necroz project team © <2015> <ArchLord2EMU>
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Author:Sagara
// Date:2015-09-06-23:29

using System;
using System.Collections.Concurrent;
using System.Linq;
using AL2Login.Configs;
using AL2Login.Interfaces;
using AL2Login.Models;
using AL2Login.Network;
using AL2Login.Network.Frames.Send;
using ArchLord2Commons.IoC;
using ArchLord2Commons.Models;
using ArchLord2Commons.Network;
using ArchLord2Commons.Utils;
using NLog;

namespace AL2Login.Services
{
    class AuthorizeService : IAuthorizeService
    {
        public static ConcurrentDictionary<int, UserModel> Online = new ConcurrentDictionary<int, UserModel>();

        private static readonly Logger Log = LogManager.GetCurrentClassLogger();

        public void Initilize()
        {
            
        }

        public void Release()
        {
            
        }

        public void CheckAuthorize(string userName, string passwordSalt, AALClient client)
        {
            using (var db = Global.GetMember<IDatabaseService>().GetFactory().OpenSession())
            {
                var model = db.QueryOver<UserModel>().Where(p => p.UserName == userName).Take(1).SingleOrDefault();
                if (model == null)
                {
                    //User not found error!
                    client.Disconnect();

                    return;
                }

                if (model.Password.ToLower().Trim() != passwordSalt.ToLower().Trim())
                {
                    //Wrong password error!
                    client.Disconnect();

                    return;
                }

                if(Online.ContainsKey(model.Identity))
                    Global.GetMember<IGsPipeService>().DisconnectMemberOnGameServer(model.Identity, model.LastGameServerId);

                string token = (model.UserName + @"8vd%h>Jxb6nVTDiU5wc2K<XK!W8>2{q]" + model.Password + new Random().Next(200000)).CalculateMd5Hash();

                var connection = (Al2Connection) client;

                model.AccessToken = token;
                connection.AccountInfo = new AccountData
                {
                    Id = model.Identity,
                    Login = model.UserName,
                    Password = model.Password,
                    ServerId = (byte) model.LastGameServerId,
                    Token = token
                };

                connection.AccountInfo.Token = token;

                db.CreateSQLQuery($"UPDATE t_users SET a_access_token=? WHERE a_id={model.Identity} ").SetString(0, model.AccessToken).ExecuteUpdate();

                if (Online.ContainsKey(model.Identity))
                {
                    UserModel toOut;

                    Online.TryGetValue(model.Identity, out toOut);

                    Online.TryUpdate(model.Identity, model, toOut);
                }
                else   
                  Online.TryAdd(model.Identity, model);

                new SfServerlist(GameServerPipeService.GetRealInfo(), model.AccessToken).Send(client, 1);
            }
        }

        public void EnterOnServerRequest(int serverId, AALClient client)
        {
            var gameServer = GameServerPipeService.GetRealInfo().First(s => s.Id == serverId);
            if(gameServer == null)
                throw new Exception($"Realm info by id:{serverId} not found");

            var connection = (Al2Connection)client;

            using (var db = Global.GetMember<IDatabaseService>().GetFactory().OpenSession())
            {
                var model = db.QueryOver<UserModel>().Where(p => p.AccessToken == connection.AccountInfo.Token).Take(1).SingleOrDefault();

                db.CreateSQLQuery($"UPDATE t_users SET a_last_server_id={serverId} WHERE a_id={model.Identity} ").ExecuteUpdate();

                new SfRequestConnection(gameServer.Id, model.AccessToken).Send(client, 1);
            }               
        }

        public void ClientDisconnected(int accountId)
        {
            UserModel toOut;

            if(Online.ContainsKey(accountId))
               Online.TryRemove(accountId, out toOut);

            else throw new Exception("Not found member on Online container");

            if(LoggingCfg.Default.MemberConnectionStatus)
                Log.Info($"Client {toOut.UserName} disconnected");
        }
    }
}
